package skewreduce.dfof;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;

import skewreduce.lib.IParticle;
import skewreduce.lib.KDTreeNode;
import skewreduce.lib.Point3D;


public final class InternalParticle
extends Point3D 
implements IParticle,KDTreeNode<InternalParticle>
{
    enum VisitState {
        NOTYET,
        PENDING,
        VISITED
    };

    protected long id;
    protected long cid;
    private VisitState visited = VisitState.NOTYET;
    private boolean allVisited;

    public InternalParticle() {}

    public InternalParticle(long i,Point3D p) {
        super(p);
        id = i;
    }

    public InternalParticle(long i,java.util.Random r) {
        super(r);
        id = i;
    }

    public InternalParticle(long i,float x,float y,float z) {
        this.id = i;
        this.x = x;
        this.y = y;
        this.z = z;
    }

    public InternalParticle(InternalParticle p) {
        id = p.getID();
        x = p.getX();
        y = p.getY();
        z = p.getZ();
        cid = p.getCluster();
    }

    public InternalParticle(IParticle p) {
        id = p.getID();
        x = p.getX();
        y = p.getY();
        z = p.getZ();
    }

    public void visit() { visited = VisitState.VISITED; }
    public void pending() { visited = VisitState.PENDING; }

    public void leave() {
        boolean l = left == null || left.allVisited;
        boolean r = right == null || right.allVisited;

        allVisited = l && r && visited != VisitState.NOTYET;
    }

    public boolean isVisited() {
        return 0 < visited.compareTo(VisitState.PENDING);
    }
    //public boolean canSkip() { return visited == VisitState.ALLVISITED; }
    public boolean canSkip() { return allVisited; }
    public boolean isPending() { return visited == VisitState.PENDING; }
    public boolean isNotVisitedYet() { return visited == VisitState.NOTYET; }

    public void write(DataOutput out) throws IOException {
        out.writeLong(id);
        out.writeLong(cid);
        super.write(out);
    }

    public void readFields(DataInput in) throws IOException {
        id = in.readLong();
        cid = in.readLong();
        super.readFields(in);
    }

    public static InternalParticle read(DataInput in) throws IOException {
        InternalParticle p = new InternalParticle();
        p.readFields(in);
        return p;
    }

    public long getCluster() { return cid; }
    public void setCluster(long cluster) { cid = cluster; }
    public boolean isAssigned() { return cid != 0; }

    public int hashCode() { return (int)id; }

    public long getID() { return id; }
    public int compareTo(IParticle x) {
        return (int)(id - x.getID());
    }

    public boolean equals(Object o) {
        if ( this == o ) return true;
        if ( o instanceof IParticle )
            return id == ((IParticle)o).getID();
        return false;
    }

    // implementation of KDTreeNode

    private InternalParticle left;
    private InternalParticle right;

    public boolean isLeaf() { return left == null && right == null; }
    public InternalParticle getLeft() { return left; }
    public InternalParticle getRight() { return right; }
    public void setLeft(InternalParticle p) { left = p; }
    public void setRight(InternalParticle p) { right = p; }
}
